home *** CD-ROM | disk | FTP | other *** search
- /* Random access file viewer. PC specific */
-
- #include "global.h"
- #include "commands.h"
- #include "session.h"
- #ifdef MSDOS
- #include <conio.h>
- #else
- #include "socket.h"
- #endif
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: view.c,v 1.19 1997/08/19 01:19:22 root Exp root $";
- #endif
-
-
- static long lineseek (FILE *fp,long offset,int nlines,int width);
- static void view (int s, void *p1, void*p2);
- extern char NoRead[];
- extern char readmeFile[];
- #ifdef UNIX
- extern int Numrows, Numcols;
- #endif
-
-
- int
- doview(argc,argv,p)
- int argc OPTIONAL;
- char *argv[];
- void *p OPTIONAL;
- {
- char fname[256];
- FILE *fp;
-
- /*allow only keyboard users to access the view command*/
- if (Curproc->input != Command->input) {
- tputs ("The 'view' command can only be executed from the command session.\nTry the 'more' command, instead!\n\n");
- return 0;
- }
-
- strncpy (fname, make_fname (Command->curdirs->dir,argv[1]), 256);
- if((fp = fopen (fname, READ_TEXT)) == NULLFILE) {
- tprintf (NoRead, fname, SYS_ERRLIST(errno));
- return 1;
- }
- (void) newproc ("view", 512, view, 0, (void *)fp, (argv[1] == readmeFile) ? (void *) strdup("Reviewing the new features file") : (void *) strdup(argv[1]),(argv[1] == readmeFile) ? 0 : 2);
- return 0;
- }
-
-
- /* Random-access file display program. Used both to read local
- * files with the "view" command, and by the FTP client to view
- * directory listings, temporary copies of read files, etc.
- */
- static void
- view (s, p1, p2)
- int s; /* If non-zero, poll interval for a changing file */
- void *p1; /* Open file pointer to read from */
- void *p2; /* If non-null, name to give to session. We free it */
- {
- struct session *sp;
- FILE *fp;
- char *name;
- int c;
- long offset = 0;
- int row,col;
- int cols;
- int rows;
- int32 polldelay = 0;
- #ifndef UNIX
- struct text_info text_info;
-
- gettextinfo (&text_info);
- cols = text_info.screenwidth;
- rows = text_info.screenheight-1; /* Allow for status line */
- #else
- cols = Numcols;
- rows = Numrows;
- #endif
-
- fp = (FILE *)p1;
- name = (char *)p2;
-
- if ((sp = newsession (name, VIEW, 0)) == NULLSESSION)
- return;
-
- if (s != 0)
- polldelay = s;
- /* Put tty into raw mode so single-char responses will work */
- sp->ttystate.echo = sp->ttystate.edit = 0;
- for ( ; ; ) {
- fseek (fp, offset, SEEK_SET);
- clrscr ();
- /* Display a screen's worth of data, keeping track of
- * cursor location so we know when the screen is full
- */
- col = row = 0;
- while ((c = getc (fp)), c != EOF) {
- switch (c) {
- case '\n': row++;
- col = 0;
- break;
- case '\t': if (col < cols - 8)
- col = (col + 8) & ~7;
- break;
- default: col++;
- break;
- }
- if (col >= cols) {
- /* Virtual newline caused by wraparound */
- col = 0;
- row++;
- }
- if (row >= rows)
- break; /* Screen now full */
- tputc ((unsigned char)c);
- }
- tflush();
- /* If we hit the end of the file and the file may be
- * growing, then set an alarm to time out the getchar()
- */
- do {
- if (feof(fp) && polldelay != 0)
- kalarm (polldelay);
- c = recvchar (Curproc->input);
- kalarm (0L); /* Cancel alarm */
- if (c != EOF || errno != EALARM)
- break; /* User hit key */
- /* Alarm timeout; see if more data arrived by
- * clearing the EOF flag, trying to read
- * another byte, and then testing EOF again
- */
- clearerr (fp);
- (void)getc (fp);
- c = ' '; /* Simulate a no-op keypress */
- } while (feof (fp));
- switch (c) {
- case 'h': /* Home */
- case 'H':
- case '<': /* For emacs users */
- offset = 0;
- break;
- case 'e': /* End */
- case '>': /* For emacs users */
- fseek (fp, 0L, SEEK_END);
- offset = lineseek (fp, ftell (fp), -rows, cols);
- break;
- case CTLD: /* Down one half screen (for VI users) */
- if (!feof (fp))
- offset = lineseek (fp, offset, rows / 2, cols);
- break;
- case CTLU: /* Up one half screen (for VI users) */
- offset = lineseek (fp, offset, -rows / 2, cols);
- break;
- case 'd': /* down line */
- case CTLN: /* For emacs users */
- case 'j': /* For vi users */
- if (!feof (fp))
- offset = lineseek (fp, offset, 1, cols);
- break;
- case 'D': /* Down page */
- case CTLV: /* For emacs users */
- if (!feof (fp))
- offset = lineseek (fp, offset, rows, cols);
- break;
- case 'u': /* up line */
- case CTLP: /* for emacs users */
- case 'k': /* for vi users */
- offset = lineseek (fp, offset, -1, cols);
- break;
- case 'U': /* Up page */
- case 'v': /* for emacs users */
- offset = lineseek (fp, offset, -rows, cols);
- break;
- case CTLC:
- case 'q':
- case 'Q':
- case ESC:
- goto done;
- default:
- break; /* Redisplay screen */
- }
- }
- done: (void) fclose (fp);
- freesession (sp);
- }
-
-
- /* Given a starting offset into an open file stream, scan forwards
- * or backwards the specified number of lines and return a pointer to the
- * new offset.
- */
- static long
- lineseek(fp,start,nlines,width)
- FILE *fp; /* Open file stream */
- long start; /* Offset to start searching backwards from */
- int nlines; /* Number of lines to move forward (+) or back (-) */
- int width; /* Screen width (max line size) */
- {
- long offset;
- long *pointers;
- int col = 0;
- int c;
- int newlines = 0;
-
- if (nlines == 0)
- return start; /* Nothing to do */
-
- if (nlines > 0) { /* Look forward requested # of lines */
- fseek (fp, start, SEEK_SET);
- col = 0;
- while ((c = getc (fp)), c != EOF) {
- switch (c) {
- case '\n': newlines++;
- col = 0;
- break;
- case '\t': if (col < width - 8)
- col = (col + 8) & ~7;
- break;
- default: col++;
- break;
- }
- if (col >= width) {
- /* Virtual newline caused by wraparound */
- col = 0;
- newlines++;
- }
- if (newlines >= nlines)
- break; /* Found requested count */
- }
- return (ftell (fp)); /* Could be EOF */
- }
- /* Backwards scan (the hardest)
- * Start back up at most (width + 2) chars/line from the start.
- * This handles full lines followed by expanded newline
- * sequences
- */
- nlines = -nlines;
- offset = (width + 2) * (nlines + 1);
- if (offset > start)
- offset = 0; /* Go to the start of the file */
- else
- offset = start - offset;
- fseek (fp, offset, SEEK_SET);
-
- /* Keep a circular list of the last 'nlines' worth of offsets to
- * each line, starting with the first
- */
- if (nlines == 0)
- return offset;
- pointers = (int32 *) callocw (sizeof(long), (unsigned) nlines);
- if (pointers == (int32*) 0)
- return start; /* shouldn't ever happen */
- pointers[newlines++ % nlines] = offset;
-
- /* Now count newlines up but not including the original
- * starting point
- */
- col = 0;
- for ( ; ; ) {
- c = getc (fp);
- switch (c) {
- case EOF: goto done;
- case '\n': col = 0;
- offset = ftell (fp);
- if (offset >= start)
- goto done;
- pointers[newlines++ % nlines] = offset;
- break;
- case '\t': if (col < width - 8)
- col = (col + 8) & ~7;
- break;
- default: col++;
- break;
- }
- if (col >= width) {
- /* Virtual newline caused by wraparound */
- col = 0;
- offset = ftell (fp);
- if (offset >= start)
- goto done;
- pointers[newlines++ % nlines] = offset;
- }
- }
-
- done:
- if (newlines >= nlines) /* Select offset pointer nlines back */
- offset = pointers[newlines % nlines];
- else /* The specified number of newlines wasn't seen, so go to the start of the file */
- offset = 0;
-
- free (pointers);
- return (offset);
- }
-